package com.example.demo;

import com.example.api.JobApi;
import com.example.api.JobExecutor;
import com.example.api.dto.ExecuteUserDTO;
import com.example.api.dto.TiggerDTO;
import com.fasterxml.jackson.databind.json.JsonMapper;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;

import java.io.IOException;
import java.util.Map;

/**
 * @author fanhang
 */
@ChannelHandler.Sharable
public class NettyHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    private static final String APPLICATION_JSON = "application/json";

    private final JsonMapper jsonMapper;
    private final JobExecutor jobExecutor;

    public NettyHttpHandler(JsonMapper jsonMapper, JobExecutor jobExecutor) {
        this.jsonMapper = jsonMapper;
        this.jobExecutor = jobExecutor;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        //100 Continue
        if (HttpUtil.is100ContinueExpected(request)) {
            ctx.write(new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.CONTINUE));
        }
        try {
            Object result = this.dispatch(request.uri(), ByteBufUtil.getBytes(request.content()));
            this.write(ctx, 200, result);
        } catch (UnsupportedOperationException e) {
            this.write(ctx, 404, Map.of("message", "not-found"));
        } catch (Exception e) {
            this.write(ctx, 500, Map.of("message", "error"));
        }
    }

    private Object dispatch(String uri, byte[] data) {
        if (uri.endsWith("/")) {
            uri = uri.substring(0, uri.length() - 1);
        }
        if (uri.startsWith(JobApi.EXECUTE_USER)) {
            return this.jobExecutor.executeUser(decode(data, ExecuteUserDTO.class));
        }
        if (uri.startsWith(JobApi.TIGGER)) {
            return this.jobExecutor.tigger(decode(data, TiggerDTO.class));
        }
        throw new UnsupportedOperationException("不支持");
    }

    private byte[] getBody(FullHttpRequest request) {
        HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), request);
        return null;
    }

    private <T> T decode(byte[] data, Class<T> clazz) {
        try {
            return jsonMapper.readValue(data, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void write(ChannelHandlerContext ctx, int status, Object data) {
        try {
            this.write(ctx, status, jsonMapper.writeValueAsBytes(data));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void write(ChannelHandlerContext ctx, int status, byte[] data) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(data));
        // 设置头信息
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, APPLICATION_JSON);
        // 将html write到客户端
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}
